﻿///------------------------------------
/// BEControlCenter MainWindowVM.cs
///------------------------------------
namespace BEControlCenter
{
    using BEControlCenter.Utilities;
    using ControlCore;
    using ControlCore.Controller;
    using ControlCore.Device;
    using System;
    using System.Collections.Generic;
    using System.ComponentModel.Composition;
    using System.ComponentModel.Composition.Hosting;
    using System.Windows;
    using System.Windows.Input;

    public class MainWindowVM : ViewModelBase
    {
        #region Private members

        /// <summary>
        /// MEF Composition container
        /// </summary>
        private readonly CompositionContainer container;

        /// <summary>
        /// Current controller
        /// </summary>
        private IController currentController;

        /// <summary>
        /// Current device
        /// </summary>
        private IDevice currentDevice;

        #endregion

        #region ctor

        /// <summary>
        /// Create instance of MainWindowVM
        /// </summary>
        public MainWindowVM()
        {
            //// Discover MEF plugins
            var catalog = new AggregateCatalog();
            catalog.Catalogs.Add(new DirectoryCatalog("Extensions"));
            container = new CompositionContainer(catalog);
            try
            {
                container.ComposeParts(this);
            }
            catch (CompositionException ce)
            {
                MessageBox.Show(ce.Message, ce.ToString());
            }

            //// Create commands
            InitCommand = new RelayCommand(param => this.init());
            ShutdownCommand = new RelayCommand(param => this.shutdown());

            //// use debuger shortcut
            this.DebugShortcut();
        }

        public override void Dispose()
        {
            if (container != null)
            {
                container.Dispose();
            }
        }

        #endregion

        #region Commands

        /// <summary>
        /// Initialize plugins command
        /// </summary>
        public ICommand InitCommand { get; private set; }

        /// <summary>
        /// Dispose plugins and close app command
        /// </summary>
        public ICommand ShutdownCommand { get; private set; }

        #endregion

        #region Public Properties

        /// <summary>
        /// A <see cref="IEnumerable{T}"/> of <see cref="Lazy{T,TMetadata}"/> of discovered controller plugins
        /// </summary>
        [ImportMany]
        public IEnumerable<Lazy<IController, IControllerMetadata>> Controllers { get; private set; }

        /// <summary>
        /// Selected controller (for binding)
        /// </summary>
        public Lazy<IController, IControllerMetadata> SelectedController { get; set; }

        /// <summary>
        /// A <see cref="IEnumerable{T}"/> of <see cref="Lazy{T,TMetadata}"/> of discovered device plugins
        /// </summary>
        [ImportMany]
        public IEnumerable<Lazy<IDevice, IDeviceMetadata>> Devices { get; private set; }

        /// <summary>
        /// Selected device (for binding)
        /// </summary>
        public Lazy<IDevice, IDeviceMetadata> SelectedDevice { get; set; }

        /// <summary>
        /// Output <see cref="FrameworkElement"/> object from controller
        /// </summary>
        public FrameworkElement ControllerOutput { get; private set; }

        /// <summary>
        /// Output <see cref="FrameworkElement"/> object from device
        /// </summary>
        public FrameworkElement DeviceOutput { get; private set; }

        #endregion

        private void init()
        {
            // Initialize controller
            if (SelectedController != null)
            {
                try
                {
                    if (currentController != null && currentController.IsInitialized)
                    {
                        currentController.Close();
                        currentController.CommandReceived -= controllerCommandReceived;
                    }

                    currentController = SelectedController.Value;
                    currentController.Init();
                    currentController.CommandReceived += controllerCommandReceived;
                    ControllerOutput = currentController.ControllerOutput;
                    OnPropertyChanged(() => this.ControllerOutput);
                }
                catch (System.NotImplementedException nie)
                {
                    MessageBox.Show(nie.Message, "Plugin feature not implemented");
                }
            }
            else
            {
                MessageBox.Show("Please select controller");
                return;
            }

            // Initialize device
            if (SelectedDevice != null)
            {
                try
                {
                    if (currentDevice != null && currentDevice.IsInitialized)
                    {
                        currentDevice.Close();
                    }

                    currentDevice = SelectedDevice.Value;
                    currentDevice.Init();
                    DeviceOutput = currentDevice.DeviceOutput;
                    OnPropertyChanged(() => this.DeviceOutput);
                }
                catch (System.NotImplementedException nie)
                {
                    MessageBox.Show(nie.Message, "Plugin feature not implemented");
                }
            }
            else
            {
                MessageBox.Show("Please select device");
                return;
            }
        }

        private void shutdown()
        {
            if (currentController != null)
            {
                try
                {
                    currentController.Close();
                }
                catch (System.NotImplementedException nie)
                {
                    MessageBox.Show(nie.Message, "Plugin feature not implemented");
                }
            }

            if (currentDevice != null)
            {
                try
                {
                    currentDevice.Close();
                }
                catch (System.NotImplementedException nie)
                {
                    MessageBox.Show(nie.Message, "Plugin feature not implemented");
                }
            }

            Application.Current.Shutdown();
        }

        private void controllerCommandReceived(object sender, ControllerCommandEventArgs e)
        {
            currentDevice.SendCommand(e.Command, e.Value);
        }

#if DEBUG
        /// <summary>
        /// This functions is used only in debug to speed up testing new code
        /// </summary>
        private void DebugShortcut()
        {
        }

#endif
    }
}
